import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import matplotlib.patches as patches

# 设置支持中文的字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

class CircularBuffer:
    def __init__(self, size):
        self.size = size
        self.buffer = [None] * size
        self.write_ptr = 0  # 写指针
        self.read_ptr = 0   # 读指针
        self.full = False
        self.empty = True
        
    def append(self, item):
        if not self.full:  # 只有在缓冲区未满时才写入
            self.buffer[self.write_ptr] = item
            self.write_ptr = (self.write_ptr + 1) % self.size
            self.empty = False
            if self.write_ptr == self.read_ptr:
                self.full = True
            return True  # 写入成功
        return False  # 缓冲区满，写入失败
            
    def read(self):
        if not self.empty:
            value = self.buffer[self.read_ptr]
            self.buffer[self.read_ptr] = None
            self.read_ptr = (self.read_ptr + 1) % self.size
            self.full = False
            if self.read_ptr == self.write_ptr:
                self.empty = True
            return value
        return None

    def get_buffer(self):
        return self.buffer.copy()

# 设置图形
fig, ax = plt.subplots(figsize=(10, 10))
buffer_size = 8
cb = CircularBuffer(buffer_size)

# 创建圆形缓冲区
theta = np.linspace(0, 2*np.pi, buffer_size, endpoint=False)
radius = 1
center = (0, 0)

# 创建扇形区域
wedges = []
for i, angle in enumerate(theta):
    wedge = patches.Wedge(center, radius, np.degrees(angle), 
                         np.degrees(angle + 2*np.pi/buffer_size), 
                         width=0.3, alpha=0.5)
    wedges.append(wedge)
    ax.add_patch(wedge)

# 添加写指针和读指针
write_arrow, = ax.plot([], [], 'g-', lw=2, label='写指针')
read_arrow, = ax.plot([], [], 'r-', lw=2, label='读指针')

# 添加文字说明
status_text = ax.text(-1.5, 1.5, '', fontsize=12)
value_texts = [ax.text(0, 0, '', ha='center', va='center') for _ in range(buffer_size)]

# 设置图形范围和样式
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)
ax.set_aspect('equal')
ax.axis('off')
ax.legend()
ax.set_title('循环缓冲区演示')

# 用于记录最后一次写入和读取的值
last_written = None
last_read = None

def update(frame):
    global last_written, last_read
    
    # 如果缓冲区满，只读取；否则随机读写
    if cb.full:
        action = 'read'
    elif cb.empty:
        action = 'write'  # 如果缓冲区空了，必须写入
    else:
        action = np.random.choice(['write', 'read'], p=[0.7, 0.3])  # 70%写，30%读
    
    if action == 'write':
        new_value = np.random.randint(1, 100)
        if cb.append(new_value):
            last_written = new_value
            status = f'操作: 写入 {new_value}\n'
        else:
            status = f'操作: 尝试写入 {new_value} 失败（缓冲区满）\n'
    else:  # 读取
        value = cb.read()
        last_read = value
        status = f'操作: 读取 {value if value is not None else "无数据"}\n'
    
    # 更新扇形颜色和值
    current_buffer = cb.get_buffer()
    for i, (wedge, val) in enumerate(zip(wedges, current_buffer)):
        wedge.set_facecolor('blue' if val is not None else 'gray')
        value_texts[i].set_position((0.85 * np.cos(theta[i]), 0.85 * np.sin(theta[i])))
        value_texts[i].set_text(str(val) if val is not None else '')
    
    # 更新写指针
    w_angle = theta[cb.write_ptr]
    write_arrow.set_data([0, radius * np.cos(w_angle)], 
                        [0, radius * np.sin(w_angle)])
    
    # 更新读指针
    r_angle = theta[cb.read_ptr]
    read_arrow.set_data([0, radius * np.cos(r_angle)], 
                       [0, radius * np.sin(r_angle)])
    
    # 更新状态文字，显示最后写入和读取的值
    status += (f'最后写入的值: {last_written if last_written is not None else "无"}\n'
               f'最后读取的值: {last_read if last_read is not None else "无"}\n'
               f'写指针位置: {cb.write_ptr}\n'
               f'读指针位置: {cb.read_ptr}\n'
               f'缓冲区满: {cb.full}\n'
               f'缓冲区空: {cb.empty}')
    status_text.set_text(status)
    
    return wedges + [write_arrow, read_arrow, status_text] + value_texts

# 创建动画
ani = FuncAnimation(fig, update, frames=range(100), interval=1000, 
                   blit=True, cache_frame_data=False)

plt.show()